In this example, we will implement a simple example of active transport. This particular model is derived from work by Jönsson et al. (2006) describing the transport of auxin. We refer to it as "transport against the gradient" because it assumes that cells are able to sense difference in auxin concentrations relative to their neighbors and relocate their auxin transporters to preferentially pump auxin towards cells of higher concentrations, i.e. the opposite direction of spontaneous diffusion/passive transport. This mechanism was proposed to explain the emergence of lateral organs at the shoot apical meristem.
In [1]:
%matplotlib notebook
In [2]:
import multicell
import numpy as np
In [3]:
sim = multicell.simulation_builder.generate_cell_grid_sim(10, 10, 1)
We define one variable called a
.
In [4]:
sim.register_cell_variable("a")
We then define the differential equation of a. This requires defining some constants and their values.
D_a is the diffusion coefficient, and T_a is the active transport coefficient.
In [5]:
sim.set_constants({"D_a": 0.03, "T_a": 1.})
In this example, the differential equation uses two built-in functions of the simulation objects: simulation.diffusion
and simulation.transport_against_gradient
. These functions automatically compute the net flows due to diffusion and active transport, respectively, for all cells. They also help the Simulation object to integrate the system of differential equations efficiently by contributing to the determination of the structure of the Jacobian matrix, as mentioned in the example about diffusion. They can therefore not be replaced by any user-defined function. User-defined function should be used through the Simulation._transport
function.
In [6]:
def da_dt(simulation, c_a, D_a, T_a, adjacency_matrix):
return simulation.diffusion(D_a, c_a, adjacency_matrix) + simulation.transport_against_gradient(T_a, c_a, adjacency_matrix)
sim.set_ODE("a", da_dt)
If we started with perfectly uniform concentrations, there would be no differences in concentrations between cells at all, and the system would remain in that unstable steady state. However, cells are not all geometrically identical (the grid is noisy), therefore their volumes are also not identical. As a consequence, we can safely initialize the quantities of matter of a
to the same value, and concentrations will automatically not be perfectly uniform.
We first need to signal the simulation that all variables have been defined and that arrays can now be reserved for their values.
In [7]:
sim.initialize_cell_variables()
We then define the array of initial quantities of matter of a
.
In [8]:
a0 = np.ones(sim.n_cells)
sim.set_cell_variable("a", a0)
In [9]:
sim.register_renderer(multicell.rendering.MatplotlibRenderer, "c_a", {"max_cmap": 17, "view": (90, -90), "axes": False})
In [10]:
sim.renderer.display("c_a")
In [11]:
sim.set_duration(20)
sim.set_time_steps(4, "linear")
sim.simulate()
Some then get absorbed by their neighbors.
In [12]:
sim.set_duration(45000)
sim.set_time_steps(3, "linear")
sim.simulate()
In simulations using larger grids, many more maxima are formed. When two maxima merge, the others shift in space as the pattern evolves towards a stabler state. This contributes to raising the computational cost of a simulations using larger grids.
In this simple case however, the two-maxima pattern appears stable, as it does not change, even after very long simulations.
In [13]:
sim.set_duration(1e8)
sim.set_time_steps(1, "linear")
sim.simulate()
We can see the tissue is no longer uniform. Two islets of higher concentrations have appeared. This shows that transport against the gradient can create heterogeneity in a tissue.
The size of the islets is dependent on the $\dfrac{D_a}{T_a}$ ratio. The higher the ratio, the larger the islets (Jönsson 2006).